package wangwenjun.phase3.executor.completablefuture.demo01;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @author ChangLiang
 * @date 2020/6/24
 */
@Slf4j
public class AppV4Test {

    private UserObject userObject;

    private DeviceObject deviceObject;

    @BeforeEach
    public void setUp() {
        userObject = new UserObject();
        userObject.setName("cl");
        userObject.setMobile("13233333333");

        deviceObject = new DeviceObject();
        deviceObject.setDeviceNo("xxxxooooo");
        deviceObject.setMobile("13233333333");
    }

    @Test
    @DisplayName("test completedFuture")
    public void test() throws InterruptedException {
        log.warn("insert start");
        /**
         * 同步执行 都是main线程执行的
         */
        boolean result;
        CompletableFuture<Boolean> future = CompletableFuture.completedFuture(DbService.insertUserTable(userObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        CompletableFuture.completedFuture(DbService.insertDeviceTable(deviceObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        try {
            result = future.get();
            log.info("insert result:{}",result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    @Test
    @DisplayName("test")
    public void test2() throws InterruptedException {
        log.warn("insert start");

        /**
         * insertUserTable 其使用main
         * insertDeviceTable 其使用ForkJoinPool 但仍旧还是依次执行的
         */

        boolean result;
        CompletableFuture<Boolean> future = CompletableFuture.completedFuture(DbService.insertUserTable(userObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        CompletableFuture.supplyAsync(()->DbService.insertDeviceTable(deviceObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        try {
            result = future.get();
            log.info("insert result:{}",result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test")
    public void test3() throws InterruptedException {
        log.warn("insert start");
        /**
         * insertUserTable 其使用ForkJoinPool thread-1
         * insertDeviceTable 其使用ForkJoinPool thread-2
         * 达到我们想要的效果
         */
        boolean result;
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(()->DbService.insertUserTable(userObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        CompletableFuture.supplyAsync(()->DbService.insertDeviceTable(deviceObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        try {
            result = future.get();
            log.info("insert result:{}",result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test")
    public void test4() throws InterruptedException {
        log.warn("insert start");
        /**
         * insertUserTable 其使用ForkJoinPool thread-1
         * insertDeviceTable 其使用ForkJoinPool thread-2
         * 测试insertDeviceTable失败并不会影响程序正常执行
         */
        boolean result;
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> DbService.insertUserTable(userObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        // 这里抛出异常了
        CompletableFuture.supplyAsync(()->DbService.insertDeviceTable(deviceObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    log.error("insert device fail deviceObj:{}",userObject.toString());
                    return false;
                });
        try {
            result = future.get();
            log.warn("insert result:{}",result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test exception")
    public void test5() throws InterruptedException {
        log.warn("insert start");
        /**
         * insertUserTable 其使用ForkJoinPool thread-1
         * insertDeviceTable 其使用ForkJoinPool thread-2
         * 测试insertDeviceTable失败并不会影响程序正常执行
         */
        boolean result;

        // 这里就直接抛出异常了
        CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(()->DbService.insertUserTable(userObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    log.error("insert user fail userObj:{}",userObject.toString());
                    return false;
                });
        CompletableFuture.supplyAsync(() -> DbService.insertDeviceTable(deviceObject))
                .exceptionally(t -> {
                    log.error(ThreadUtil.exceptionToString(t));
                    return false;
                });
        try {
            result = future.get();
            log.info("insert result:{}",result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        Thread.currentThread().join();
    }
}
